from django.shortcuts import render

# Create your views here.
from random import choice

from rest_framework.viewsets import GenericViewSet
from rest_framework.mixins import CreateModelMixin, RetrieveModelMixin, UpdateModelMixin
from rest_framework import status
from rest_framework.response import Response
from rest_framework import generics
from rest_framework.permissions import IsAuthenticated
from rest_framework import authentication
from utils.permissions import IsOwnerOrReadOnly
from rest_framework_jwt.authentication import JSONWebTokenAuthentication

# jwt 生成 token的方法
from rest_framework_jwt.serializers import jwt_encode_handler, jwt_payload_handler

from django.db.models import Q
from django.contrib.auth.backends import ModelBackend
from django.contrib.auth import get_user_model
User = get_user_model()

from .serializers import SmsSerializer, RegisterSerializer, UserInfoSerializer, UserInfoModifySerializer
from .models import VerifyCode
from utils.message_code import YunPian


class CustomBackend(ModelBackend):
    """
    自定用户验证
    需要在 settings 中配置
    """
    def authenticate(self, username=None, password=None, **kwargs):
        try:
            user = User.objects.get(Q(username=username)|Q(mobile=username))
            if user.check_password(password):
                return user
        except Exception as e:
            return None


class SmsCodeViewset(CreateModelMixin, GenericViewSet):
    """
    短信验证码
    """
    serializer_class = SmsSerializer

    def generate_code(self):
        """
        生成4位数的验证码
        :return:
        """
        SEEDS = "1234567890"
        random_str = []
        for i in range(4):
            random_str.append(choice(SEEDS))
        return "".join(random_str)

    def create(self, request, *args, **kwargs):
        """
        重写创建方法
        :param request:
        :param args:
        :param kwargs:
        :return:
        """
        serializer = self.get_serializer(data=request.data)

        # raise_exception=True 设置后，如果验证信息不满足 serializer_class 中的验证，会直接抛异常，不会执行之后的代码
        serializer.is_valid(raise_exception=True)

        mobile = serializer.validated_data["mobile"]  # 从 serializer 中取数据（经过验证的）

        # 云片网：cfb11000d16b4c888b2d0d81a425c21b
        APIKEY = "cfb11000d16b4c888b2d0d81a425c21b"
        yun_pian = YunPian(APIKEY)

        code = self.generate_code()

        sms_status = yun_pian.send_sms(code=code, mobile=mobile)  # 调用验证码发送

        # 判断短信是否发送成功
        if sms_status["code"] != 0:
            return Response({
                "mobile": sms_status["msg"]
            }, status=status.HTTP_400_BAD_REQUEST)
        else:
            """
            发送成功后将数据保存到数据库中
            """
            code_record = VerifyCode(code=code, mobile=mobile)
            code_record.save()
            return Response({
                "mobile": mobile
            }, status=status.HTTP_201_CREATED)


class RegisterViewset(CreateModelMixin, RetrieveModelMixin, GenericViewSet):
    """
    新建用户
    """
    serializer_class = RegisterSerializer
    queryset = User.objects.all()

    # 重载 create 函数，为了让用户注册后返回token
    def create(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)

        # 给返回值里面多加一个token
        user = self.perform_create(serializer)
        payload = jwt_payload_handler(user)  # 负载
        re_dict = serializer.data
        re_dict["token"] = jwt_encode_handler(payload)
        re_dict["name"] = user.name if user.name else user.username

        headers = self.get_success_headers(serializer.data)
        return Response(re_dict, status=status.HTTP_201_CREATED, headers=headers)

    def get_object(self):
        return self.request.user

    # 重载 perform_create 函数，为了返回user
    def perform_create(self, serializer):
        return serializer.save()


class UserInfoAPIView(generics.GenericAPIView, UpdateModelMixin):
    """
    用户信息
    """
    queryset = User.objects.all()
    serializer_class = UserInfoSerializer

    authentication_classes = (authentication.SessionAuthentication,)  # 用浏览器调试更方便
    permission_classes = (IsAuthenticated, IsOwnerOrReadOnly,)  # 限制权限，只有登录的用户才可以调用，IsOwnerOrReadOnly只能访问自己相关的数据
    authentication_classes = (JSONWebTokenAuthentication, authentication.SessionAuthentication )  # 配置验证使用 JWT 验证

    def get(self, request, *args, **kwargs):
        print(request.method)
        instance = self.get_object()
        serializer = self.get_serializer(instance)
        return Response(serializer.data)

    def post(self, request, *args, **kwargs):
        partial = kwargs.pop('partial', False)
        instance = self.get_object()
        serializer = self.get_serializer(instance, data=request.data, partial=partial)
        serializer.is_valid(raise_exception=True)
        self.perform_update(serializer)

        if getattr(instance, '_prefetched_objects_cache', None):
            # If 'prefetch_related' has been applied to a queryset, we need to
            # forcibly invalidate the prefetch cache on the instance.
            instance._prefetched_objects_cache = {}

        return Response(serializer.data)

    def get_object(self):
        return self.request.user

    def perform_update(self, serializer):
        serializer.save()

    def partial_update(self, request, *args, **kwargs):
        kwargs['partial'] = True
        return self.update(request, *args, **kwargs)


class UserInfoModifyAPIView(generics.GenericAPIView, UpdateModelMixin):
    """
    修改用户信息
    """
    queryset = User.objects.all()
    serializer_class = UserInfoModifySerializer

    authentication_classes = (authentication.SessionAuthentication,)  # 用浏览器调试更方便
    permission_classes = (IsAuthenticated, IsOwnerOrReadOnly,)  # 限制权限，只有登录的用户才可以调用，IsOwnerOrReadOnly只能访问自己相关的数据
    authentication_classes = (JSONWebTokenAuthentication, authentication.SessionAuthentication )  # 配置验证使用 JWT 验证

    def post(self, request, *args, **kwargs):
        partial = kwargs.pop('partial', False)
        instance = self.get_object()
        serializer = self.get_serializer(instance, data=request.data, partial=partial)
        serializer.is_valid(raise_exception=True)
        self.perform_update(serializer)

        if getattr(instance, '_prefetched_objects_cache', None):
            # If 'prefetch_related' has been applied to a queryset, we need to
            # forcibly invalidate the prefetch cache on the instance.
            instance._prefetched_objects_cache = {}

        return Response(serializer.data)

    def get_object(self):
        return self.request.user

    def perform_update(self, serializer):
        serializer.save()

    def partial_update(self, request, *args, **kwargs):
        kwargs['partial'] = True
        return self.update(request, *args, **kwargs)
